#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace Weazel.Gezel.Model
{
  /// <summary>
  /// Represents a single state in a finite state 
  /// machine controller, it does not add functionality
  /// or data to its base class.
  /// </summary>
  public class State : AbstractEntity<Controller>
  {
    public State(Controller parent, string name) : base(parent, name)
    {
    }

		public State(
			Controller parent, 
			string name, 
			Position startPosition,
			Position endPosition
		)
			: base(parent, name, startPosition, endPosition)
    {
    }
  } 

  /// <summary>
  /// Represents one of the three gezel controller types as
  /// indicated by the ControllerType field
  /// </summary>
  public partial class Controller : AbstractEntity<Model>
  {
    /// <summary>
    /// Enumerates the three supported
    /// controller types.
    /// </summary>
    public enum ControllerType
    {
      Hardwired, Sequencer, Fsm
    }

    /// <summary>
    /// The initial state in case
    /// the controller is a fsm type
    /// controller
    /// </summary>
    private State initialState;
    public State InitialState
    {
      get
      {
        return initialState;
      }
      set
      {
        initialState = value;
        states[value.LocalName] = value;
      }
    }

    /// <summary>
    /// Records the set of states in case the
    /// controller is a fsm type controller
    /// </summary>
    private Dictionary<string, State> states;
    public Dictionary<string, State> States
    {
      get
      {
        return states;
      }
    }

    /// <summary>
    /// Contains the set of possible top-level transition 
    /// (which may in turn contain nested transitions) if
    /// the controller is of type fsm
    /// </summary>
    private Dictionary<string, Transition> transitions;
    public Dictionary<string, Transition> Transitions
    {
      get
      {
        return transitions;
      }
    }

    /// <summary>
    /// The type of controller
    /// </summary>
    private ControllerType type;
    public ControllerType Type
    {
      get
      {
        return type;
      }
      set
      {
        type = value;
      }
    }

    /// <summary>
    /// Stores string references to signalflowgraphs
    /// in the datapath the controller governs execution of
    /// </summary>
    private List<string> sfgRefs;
    public List<string> SignalFlowGraphRefs
    {
      get
      {
        return sfgRefs;
      }
    }

    /// <summary>
    /// The name of the datapath controlled
    /// by this controller instance
    /// </summary>
    private string datapathRef;
    public string DatapathRef
    {
      get
      {
        return datapathRef;
      }
      set
      {
        datapathRef = value;
      }
    }

    /// <summary>
    /// The datapath controlled by this
    /// controller instance. Note that this
    /// reference is not set until verification
    /// has been performed
    /// </summary>
    private Datapath datapath;
    public Datapath Datapath
    {
      get
      {
        return datapath;
      }
    }

    /// <summary>
    /// Maps from the signalflowgraph reference names
    /// to the corresponding SignalFlowGraph instances
    /// </summary>
    private Dictionary<string, SignalFlowGraph> sfgs;
    public Dictionary<string, SignalFlowGraph> SignalFlowGraphs
    {
      get
      {
        return sfgs;
      }
    }

		public Controller(
			Model parent, 
			string name, 
			Position startPosition,
			Position endPosition
		)
			: this(parent, name)
    {
			this.startPosition = startPosition;
			this.endPosition = endPosition;
    }

    /// <summary>
    /// Constructs a new controller with the specified
    /// model as parent and with the given local name
    /// </summary>
    /// <param name="parent">the model which contains the controller</param>
    /// <param name="name">local name of the controller</param>
    public Controller(Model parent, string name) : base(parent, name)
    {
      this.sfgRefs = new List<string>();
      this.states = new Dictionary<string, State>();
      this.transitions = new Dictionary<string, Transition>();
    }

    public virtual Controller Clone(string newDatapathRef)
    {
      Controller clone = 
				new Controller(parent, localName, startPosition, endPosition);

      clone.datapathRef = newDatapathRef;
      clone.sfgRefs.AddRange(sfgRefs);
			clone.type = type;

			// note: reference copy, ok?
			clone.transitions = this.transitions;
			clone.states = this.states;
			clone.initialState = this.initialState;
		
      return clone;
    }
  }
}